﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Dukous.Domain;

namespace Dukous.Security.Domain
{
    /// <summary>
    /// 安全对象
    /// </summary>
    [Serializable]
    public class SecurityObject : Entity<long>
    {
        /// <summary>
        /// 获取 / 设置 类名称
        /// </summary>
        public virtual string ClassName { get; set; }

        /// <summary>
        /// 获取 / 设置 类全名称
        /// </summary>
        public virtual string FullName { get; set; }

        /// <summary>
        /// 获取 / 设置 安全对象字段集合
        /// </summary>
        public virtual IList<SecurityObjectField> Fields { get; set; }

        /// <summary>
        /// 获取 / 设置 安全对象权限集合
        /// </summary>
        public virtual IList<SecurityObjectPermission> SecurityObjectPermissions { get; set; }

        public virtual bool Check(User user, string permission)
        {
            return this.Check(user, permission, null);
        }

        public virtual bool Check(User user, string permission, string field)
        {
            SecurityObjectPermission securityObjectPermission = null;

            if (string.IsNullOrEmpty(field))
            {
                securityObjectPermission = this.SecurityObjectPermissions.Where(x => x.Permission.Name == permission
                                                                    && x.Users.Contains(user)).FirstOrDefault();
            }
            else
            {
                securityObjectPermission = this.SecurityObjectPermissions.Where(x => x.Permission.Name == permission
                                                                    && x.Users.Contains(user)
                                                                    && x.Fields.Select(y => y.FieldName).Contains(field)).FirstOrDefault();
            }

            return securityObjectPermission != null ? true : Check(user.Groups, permission, field);
        }

        public virtual bool Check(Group group, string permission)
        {
            return this.Check(group, permission, null);
        }

        public virtual bool Check(Group group, string permission, string field)
        {
            SecurityObjectPermission securityObjectPermission = null;

            if (string.IsNullOrEmpty(field))
            {
                securityObjectPermission = this.SecurityObjectPermissions.Where(x => x.Permission.Name == permission 
                                                                    && x.Groups.Contains(group)).FirstOrDefault();
            }
            else
            {
                securityObjectPermission = this.SecurityObjectPermissions.Where(x => x.Permission.Name == permission
                                                                    && x.Groups.Contains(group)
                                                                    && x.Fields.Select(y => y.FieldName).Contains(field)).FirstOrDefault();
            }

            return securityObjectPermission != null ? true : InternalCheck(group.Parent, permission, field);
        }

        public virtual bool Check(IList<Group> groups, string permission, string field)
        {
            foreach (var group in groups)
            {
                if (this.Check(group, permission, field))
                {
                    return true;
                }
                else
                {
                    if (InternalCheck(group.Parent, permission, field))
                    {
                        return true;
                    }
                }
            }

            return false;
        }

        private bool InternalCheck(Group group, string permission, string field)
        {
            if (permission == null)
            {
                return true;
            }

            if (group != null)
            {
                SecurityObjectPermission securityObjectPermission = null;
                if (string.IsNullOrEmpty(field))
                {
                    securityObjectPermission = this.SecurityObjectPermissions.Where(x => x.Permission.Name == permission 
                                                                        && x.Groups == group 
                                                                        && x.Inheritable == true).FirstOrDefault();
                }
                else
                {
                    securityObjectPermission = this.SecurityObjectPermissions.Where(x => x.Permission.Name == permission
                                                                        && x.Groups == group
                                                                        && x.Inheritable == true
                                                                        && x.Fields.Select(y => y.FieldName).Contains(field)).FirstOrDefault();
                }
                if (securityObjectPermission == null)
	            {
                    if (group.Parent != null)
                    {
                        return this.InternalCheck(group.Parent, permission, field);
                    }

                    return false;
	            }

                return true;
            }

            return false;
        }

        private bool InternalCheck(IList<Group> groups, string permission, string field)
        {
            if (permission == null)
            {
                return true;
            }

            if (groups != null)
            {
                foreach (var group in groups)
                {
                    if (InternalCheck(group, permission, field))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
    }
}
